with Ada.Strings.Unbounded;
use Ada.Strings.Unbounded;
with Coordinates;
use Coordinates;
with Generic_Sorted_List;
-------------------------------------------------
-- Parts.Operations paketets implementation.   --
-------------------------------------------------
package body Parts.Operations is

   function Create_Part_List(Input : in String_Array)
                            return Part_List.List_Pointer is
      List : Part_List.List_Pointer;
      New_Part : Part_Type;
      New_Coord : Coordinate_Type;
      Part_count, Field_Count, Coord_Count, Count, X, Y, Z : Integer;
      Str : String(1..100);
      In_String : String(1..100);
   begin
      Field_Count := Integer'Value(To_String(input(1)))*2;
      -- Antal fält som skall läsas av är 2 gånger antalet bitar.
      Part_Count := 1;
      for Antal in 2..Field_Count+1 loop
         In_String(1..Length(Input(Antal))) := To_String(Input(Antal));

         if (Antal mod 2 = 0) then
            -- Fulkod som inte klarar 2-siffriga tal i dimensionerna.
            X := Integer'Value(In_String(1..1));
            Y := Integer'Value(In_String(3..3));
            Z := Integer'Value(In_String(5..5));
         else
            Count := 1;
            Coord_Count :=1;
            for I in 1..Z loop
               for J in 1..Y loop
                  for K in 1..X loop
                     if In_String(Count) = '1' then
                        Set_Number(New_Coord, Coord_Count);
                        Set_Coordinates(New_Coord, (K-1), (J-1), (I-1));
                        --Put(New_Coord);
                        Insert(New_Part.Coordinates, New_Coord);
                        Coord_Count := Coord_Count + 1;
                     end if;
                     Count := Count+1;
                  end loop;
               end loop;
            end loop;
            New_Part.Part_Nr := Part_Count;
            New_Part.X := X;
            New_Part.Y := Y;
            New_Part.Z := Z;
            Insert(List, New_Part);
            New_Part.Coordinates := null;
            Part_Count := Part_Count +1;
         end if;
      end loop;
      return List;
   end Create_Part_List;

   -------------------------------------------------
   -- Eventuellt skall dessa procedurer för       --
   -- rotation och translation implementeras här. --
   -------------------------------------------------

   procedure Rotate_Part(Coord_List : in out Coordinate_List.List_Pointer;
                         Rotation_Angle : in Float;
                         Rotation_Axis : in Character) is
      Tmp : Coordinate_Type;
      C_Tmp : Int_Vector;
   begin
      -- FULKODAT! istället för att modifiera koordinaten direkt så skapar den
      -- en kopia och byter ut den gamla...
      for I in 1..Length(Coord_List) loop
         Tmp := Find(Coord_List, I);
         --Coordinate_List.Find(Coord, I, Tmp);
         C_Tmp := Get_Coordinates(Tmp);
         Rotate_Single_Point_Around_Axis(C_Tmp,
                                         Rotation_Angle,
                                         Rotation_Axis);
         Set_Coordinates(Tmp, C_Tmp(1), C_Tmp(2), C_Tmp(3));
         Remove(Coord_List, I);
         Insert(Coord_List, Tmp);
      end loop;
      --/ END FULKOD

      --        while not Empty(Coord) loop
      --           Rotate_Single_Point_Around_Axis(Coord.Data.Coordinates,
      --                                           Rotation_Angle,
      --                                           Rotation_Axis);
      --           Coord := Coord.Next;
      --        end loop;
   end Rotate_Part;

   procedure Move_Part(Coord_List : in out Coordinate_List.List_Pointer;
                       X, Y, Z : in Integer) is
      Tmp : Coordinate_Type;
      C_Tmp : Int_Vector;
   begin
      -- FULKODAT! istället för att modifiera koordinaten direkt så skapar den
      -- en kopia och byter ut den gamla...
        for I in 1..Length(Coord_List) loop
        Tmp := Find(Coord_List, I);
        --Coordinate_List.Find(Coord, I, Tmp);
        C_Tmp := Get_Coordinates(Tmp);
        Move_Single_point(C_Tmp, X, Y, Z);
        Set_Coordinates(Tmp, C_Tmp(1), C_Tmp(2), C_Tmp(3));
        Remove(Coord_List, I);
        Insert(Coord_List, Tmp);
        end loop;
        --/ END FULKOD

        --      while not Empty(Coord) loop
        --           Move_Single_Point(Coord.Data.Coordinates, X, Y, Z);
        --           Coord := Coord.Next;
        --        end loop;
   end Move_Part;

   function Move_Part(Coord_List : in Coordinate_List.List_Pointer;
                      X, Y, Z : in Integer)
                     return Coordinate_List.List_Pointer is
      Temp_Coord_List : Coordinate_List.List_Pointer;
   begin
      Temp_Coord_List := Copy(Coord_List);
      Move_Part(Temp_Coord_List, X, Y, Z);
      return Temp_Coord_List;
   end Move_Part;

   function Member(Left : in Coordinate_List.List_Pointer;
                   Right : in Coordinate_List.List_Pointer) return Boolean is
        L_Coord, R_Coord : Int_Vector;
      Tmp_Coord_Left, Tmp_Coord_Right : Coordinate_Type;
   begin
      for Outer in 1..Length(Left) loop
         Tmp_Coord_Left := Find(left, outer);
         L_Coord := Get_Coordinates(Tmp_Coord_Left);
         for Inner in 1..Length(Right) loop
            Tmp_Coord_Right := Find(Right, Inner);
            R_Coord := Get_Coordinates(Tmp_Coord_Right);
            exit when (L_Coord = R_Coord);
            if Inner = Length(Right) then
               return False;
            end if;
         end loop;
      end loop;
      return True;

   end Member;



end Parts.Operations;

